/*
 * Copyright (c) 2016. For Intelligent Group.
 */

package com.intelligent.mts.da.utils;

import com.google.common.collect.Lists;
import com.intelligent.mts.common.mapper.JsonMapper;
import com.intelligent.mts.core.dto.SerialNumberDto;
import com.intelligent.mts.core.dto.TrackDto;
import com.intelligent.mts.core.service.DataSearchService;
import com.intelligent.mts.core.utils.AppConst;
import com.intelligent.mts.da.message.BaseDto;
import com.intelligent.mts.da.message.ProcessMessage;
import com.intelligent.mts.da.message.ReceiveMessage;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by julia on 16/7/21.
 */
public class MessageUtils {

    public static Logger logger = LoggerFactory.getLogger(MessageUtils.class);

    private static List<String> startFlags;
    private static JsonMapper mapper = JsonMapper.nonDefaultMapper();


    public static ReceiveMessage decodeMessage(String message) throws Exception {
        if (StringUtils.isBlank(message)) {
            logger.error("Message is empty.");
            return null;
        }
        message = message.trim();
        String endFlag = message.substring(message.length() - 1, message.length());
        String[] messages =  message.substring(0, message.length() - 1).split(";");

        if (messages == null || messages.length == 0) {
            logger.error("Message is empty.");
            return null;
        }

        String startFlag = messages[0];

        if (!getStartFlags().contains(startFlag) ||  messages.length < 3 || !endFlag.contains(AppConst.END_FLAG)) {
            logger.error("Message format error.");
            return null;
        }

        Map<String, String> snLists = new HashMap<>();
        Map<String, String> pnLists = new HashMap<>();
        ReceiveMessage receiveMessage = new ReceiveMessage();
        receiveMessage.setStartFlag(startFlag);
        receiveMessage.setLineId(messages[1]);
        receiveMessage.setStationId(messages[2]);
        String data = "";
        String result = "";
        if(!AppConst.START_HEARTBEAT.equals(startFlag)){
            for (int i = 3; i < messages.length; i ++) {
                String message1 = messages[i];
                message1 = message1.trim();

                if (StringUtils.isBlank(message1)) {
                    continue;
                }

                if ((AppConst.RESULT_OK.equals(message1) || AppConst.RESULT_NG.equals(message1))) {
                    result += message1;
                    receiveMessage.setResult(result);
                    continue;
                }

                if (messages[2].equals(AppConst.STATION_1060) && startFlag.equals(AppConst.START_STATUS_REQ)){
                    if (message1.contains("=")){
                        String snName = message1.split("=")[0];
                        String snValue = message1.split("=")[1];
                        if (StringUtils.isBlank(snName) || StringUtils.isBlank(snValue)){
                            logger.error("Serialnumber or snValue is empty" , snName, snValue);
                            return null;
                        }
                        receiveMessage.setHou(snValue);
                        snLists.put(AppConst.SN_HOU, snValue);
                        receiveMessage.setSnLists(snLists);
                        receiveMessage.setPnLists(pnLists);
                    }
                }else if (message1.contains("=") && message1.matches("\\p{ASCII}+!\\p{ASCII}+!\\p{ASCII}+")) {
                    String snName = message1.split("=")[0];
                    String snpn = message1.split("=")[1];
                    if (StringUtils.isBlank(snpn)){
                        logger.error("Value is empty" );
                        return null;
                    }
                    int LengthSnpn = snpn.length();
                    String snValue1 = snpn.split("!")[1];
                    String snValue = snpn;
                    int Lengthsn = snValue1.length();
                    String pnValue = snpn.substring(Lengthsn + 2, LengthSnpn);
                    if (pnValue.substring(pnValue.length()-1,pnValue.length()) .equals("!") ){
                        logger.error("product number is not corret");
                        return null;
                    }
                    if (StringUtils.isBlank(snName) || StringUtils.isBlank(snValue) || StringUtils.isBlank(pnValue)){
                        logger.error("Serialnumber or snValue or pnValue is empty" , snName, snValue, pnValue);
                        return null;
                    }
                    switch(snName) {
                        case AppConst.SN_PCBA :
                            pnValue = pnValue.substring(0,pnValue.length()-1);
                            receiveMessage.setPcba(snValue);
                            receiveMessage.setPcbaPn(pnValue);
                            snLists.put(AppConst.SN_PCBA, snValue);
                            pnLists.put(AppConst.SN_PCBA, pnValue);
                            break;
                        case AppConst.SN_HS:
                            receiveMessage.setHs(snValue);
                            receiveMessage.setHsPn(pnValue);
                            snLists.put(AppConst.SN_HS, snValue);
                            pnLists.put(AppConst.SN_HS, pnValue);
                            break;
                        case AppConst.SN_HOU :
                            receiveMessage.setHou(snValue);
                            receiveMessage.setHouPn(pnValue);
                            snLists.put(AppConst.SN_HOU, snValue);
                            pnLists.put(AppConst.SN_HOU, pnValue);
                            break;
                        case AppConst.SN_GW :
                            receiveMessage.setGw(snValue);
                            receiveMessage.setGwPn(pnValue);
                            snLists.put(AppConst.SN_GW, snValue);
                            pnLists.put(AppConst.SN_GW, pnValue);
                            break;
                        case AppConst.SN_DSP_P:
                            receiveMessage.setDsp_p(snValue);
                            receiveMessage.setDsp_pPn(pnValue);
                            snLists.put(AppConst.SN_DSP_P, snValue);
                            pnLists.put(AppConst.SN_DSP_P, pnValue);
                            break;
                        case AppConst.SN_DSP_S:
                            receiveMessage.setDsp_s(snValue);
                            receiveMessage.setDsp_sPn(pnValue);
                            snLists.put(AppConst.SN_DSP_S, snValue);
                            pnLists.put(AppConst.SN_DSP_S, pnValue);
                            break;
                        case AppConst.FG_END:
                            receiveMessage.setFg(snValue);
                            receiveMessage.setFgpn(pnValue);
                            snLists.put(AppConst.FG_END,snValue);
                            pnLists.put(AppConst.FG_END,pnValue);
                            receiveMessage.setData(data + receiveMessage.getResult());
                            receiveMessage.setSnLists(snLists);
                            receiveMessage.setPnLists(pnLists);
                            return receiveMessage;
                       /* case AppConst.ORDER :
                            receiveMessage.setOrderId(snValue);
                            break;
                            */
                        default:
                            data += message1 + ";";
                    }
                } else if (message1.contains("="))
                   {
                       String OrderIdName = message1.split("=")[0];
                       String OrderIdValue = message1.split("=")[1];
                       if (OrderIdName.equals(AppConst.ORDER))
                       {
                           receiveMessage.setOrderId(OrderIdValue);
                       }
                       else {
                           result += message1;
                           result += ";";
                       }
                   }
            }
            if (result != null && !result.equals(""))
            {
                int resultLenth = result.split(";").length;
                if (!AppConst.RESULT_OK.equals(result.split(";")[resultLenth-1]) && !AppConst.RESULT_NG.equals(result.split(";")[resultLenth-1])){
                    return null;
                }
                receiveMessage.setResult(result);
            }
            if (snLists.isEmpty() ) {
                logger.error("Serial number is empty.");
                return null;
            }
            if (!messages[2].equals(AppConst.STATION_1060) && pnLists.isEmpty()) {
                logger.error("Product number is empty.");
                return null;
            }
        }

        if ((AppConst.START_STATUS_REQ.equals(startFlag) || AppConst.START_DATA_REQ.equals(startFlag)) && StringUtils.isBlank(receiveMessage.getResult())) {
            logger.error("Result is empty.");
            return null;
        }

        if (AppConst.START_DATA_REQ.equals(startFlag) && StringUtils.isBlank(receiveMessage.getOrderId())) {
            logger.error("OrderId is empty.");
            return null;
        }

        receiveMessage.setData(data + receiveMessage.getResult());
        receiveMessage.setSnLists(snLists);
        receiveMessage.setPnLists(pnLists);
        return receiveMessage;
    }

    public static boolean isValidate(ReceiveMessage currentMessage, ReceiveMessage preMessage) {
        if (currentMessage == null || preMessage == null) {
            return false;
        }
        String stationId = currentMessage.getStationId();
        if (currentMessage.getStationId().equals(preMessage.getStationId())
        && currentMessage.getLineId().equals(preMessage.getLineId())) {
            switch(stationId) {
                case AppConst.STATION_1060:
                    boolean SnisSameKey1 = false;
                    boolean SnisSameValue1 = false;
                    if (currentMessage.getSnLists() != null && !currentMessage.getSnLists().isEmpty()){
                        for (String currentSn : currentMessage.getSnLists().keySet()) {
                            for (String preSn : preMessage.getSnLists().keySet()) {
                                if (currentSn.equals(preSn)) {
                                    SnisSameKey1 = true;
                                } else {
                                    logger.error("Serialnumber is not match, current serialnumber:[{}], previous serialnumber:[{}]", currentSn, preSn);
                                    break;
                                }
                                if (currentMessage.getSnLists().get(currentSn).equals(preMessage.getSnLists().get(preSn))) {
                                    SnisSameValue1 = true;
                                } else {
                                    logger.error("Serialnumber value is not match, current serialnumber:[{}], previous serialnumber:[{}]", currentMessage.getSnLists().get(currentSn), preMessage.getSnLists().get(preSn));
                                    break;
                                }
                            }
                        }
                    }
                    if(SnisSameKey1 && SnisSameValue1){
                        return true;
                    }

               /* case AppConst.STATION_0420 :
                    if (StringUtils.isNotBlank(currentMessage.getHou()) && StringUtils.isNotBlank(preMessage.getHou())
                            && currentMessage.getHou().equals(preMessage.getHou())) {
                        return true;
                    }
                    logger.error("HOU is empty, serialnumber:[{}]", preMessage.getHou());
                    break;
                case AppConst.STATION_0430:
                    if (StringUtils.isNotBlank(currentMessage.getHou()) && StringUtils.isNotBlank(preMessage.getHou())
                            && currentMessage.getHou().equals(preMessage.getHou())) {
                        return true;
                    }
                    logger.error("HOU is empty, serialnumber:[{}]", preMessage.getHou());
                    break;
                case AppConst.STATION_0450 :
                    if (StringUtils.isNotBlank(currentMessage.getHou()) && StringUtils.isNotBlank(preMessage.getHou())
                            && currentMessage.getHou().equals(preMessage.getHou())) {
                        return true;
                    }
                    logger.error("HOU is empty, serialnumber:[{}]", preMessage.getHou());
                    break;
                case AppConst.STATION_0610 :
                    if (StringUtils.isNotBlank(currentMessage.getPcba()) && StringUtils.isNotBlank(preMessage.getPcba())
                            && currentMessage.getPcba().equals(preMessage.getPcba())) {
                        return true;
                    }
                    logger.error("PCBA is empty, serialnumber:[{}]", preMessage.getPcba());
                    break;
                case AppConst.STATION_0620 :
                    if (StringUtils.isNotBlank(currentMessage.getPcba()) && StringUtils.isNotBlank(preMessage.getPcba())
                            && currentMessage.getPcba().equals(preMessage.getPcba())) {
                        return true;
                    }
                    logger.error("PCBA is empty, serialnumber:[{}]", preMessage.getPcba());
                    break;
                case AppConst.STATION_0650 :
                    if (StringUtils.isNotBlank(currentMessage.getHs()) && StringUtils.isNotBlank(preMessage.getHs())
                            && currentMessage.getHs().equals(preMessage.getHs())) {
                        return true;
                    }
                    logger.error("HS is empty, serialnumber:[{}]", preMessage.getHs());
                    break;
                case AppConst.STATION_0680 :
                    break;
                case AppConst.STATION_0690 :
                    if (StringUtils.isNotBlank(currentMessage.getHs()) && StringUtils.isNotBlank(preMessage.getHs())
                            && currentMessage.getHs().equals(preMessage.getHs())) {
                        return true;
                    }
                    logger.error("HS is empty, serialnumber:[{}]", preMessage.getHs());
                    break;
                case AppConst.STATION_0730 :
                    if (StringUtils.isNotBlank(currentMessage.getHs()) && StringUtils.isNotBlank(preMessage.getHs())
                            && currentMessage.getHs().equals(preMessage.getHs())) {
                        return true;
                    }
                    logger.error("HS is empty, serialnumber:[{}]", preMessage.getHs());
                    break;
                case AppConst.STATION_0930 :
                    if (StringUtils.isNotBlank(currentMessage.getHs()) && StringUtils.isNotBlank(preMessage.getHs())
                            && currentMessage.getHs().equals(preMessage.getHs())) {
                        return true;
                    }
                    logger.error("HS is empty, serialnumber:[{}]", preMessage.getHs());
                    break;
                case AppConst.STATION_0950 :
                    if (StringUtils.isNotBlank(currentMessage.getHou()) && StringUtils.isNotBlank(preMessage.getHou())
                            && currentMessage.getHou().equals(preMessage.getHou())) {
                        return true;
                    }
                    logger.error("HOU is empty, serialnumber:[{}]", preMessage.getHou());
                    break;
                case AppConst.STATION_0970 :
                    if (StringUtils.isNotBlank(currentMessage.getHou()) && StringUtils.isNotBlank(preMessage.getHou())
                            && currentMessage.getHou().equals(preMessage.getHou())) {
                        return true;
                    }
                    logger.error("HOU is empty, serialnumber:[{}]", preMessage.getHou());
                    break;
                case AppConst.STATION_0990 :
                    if (StringUtils.isNotBlank(currentMessage.getHou()) && StringUtils.isNotBlank(preMessage.getHou())
                            && currentMessage.getHou().equals(preMessage.getHou())) {
                        return true;
                    }
                    logger.error("HOU is empty, serialnumber:[{}]", preMessage.getHou());
                    break;
                case AppConst.STATION_1010 :
                    if (StringUtils.isNotBlank(currentMessage.getHou()) && StringUtils.isNotBlank(preMessage.getHou())
                            && currentMessage.getHou().equals(preMessage.getHou())) {
                        return true;
                    }
                    logger.error("HOU is empty, serialnumber:[{}]", preMessage.getHou());
                    break;
                case AppConst.STATION_1020 :
                    if (StringUtils.isNotBlank(currentMessage.getHou()) && StringUtils.isNotBlank(preMessage.getHou())
                            && currentMessage.getHou().equals(preMessage.getHou())) {
                        return true;
                    }
                    logger.error("HOU is empty, serialnumber:[{}]", preMessage.getHou());
                    break;
                case AppConst.STATION_1030 :
                    if (StringUtils.isNotBlank(currentMessage.getHou()) && StringUtils.isNotBlank(preMessage.getHou())
                            && currentMessage.getHou().equals(preMessage.getHou())) {
                        return true;
                    }
                    logger.error("HOU is empty, serialnumber:[{}]", preMessage.getHou());
                    break;
                case AppConst.STATION_1050 :
                    if (StringUtils.isNotBlank(currentMessage.getHou()) && StringUtils.isNotBlank(preMessage.getHou())
                            && currentMessage.getHou().equals(preMessage.getHou())) {
                        return true;
                    }
                    logger.error("HOU is empty, serialnumber:[{}]", preMessage.getHou());
                    break;
                case AppConst.STATION_1060 :
                    if (StringUtils.isNotBlank(currentMessage.getHou()) && StringUtils.isNotBlank(preMessage.getHou())
                            && currentMessage.getHou().equals(preMessage.getHou())) {
                        return true;
                    }
                    logger.error("HOU is empty, serialnumber:[{}]", preMessage.getHou());
                    break;*/
                default:
                    boolean SnisSameKey = false;
                    boolean SnisSameValue = false;
                    boolean PnisSameKey = false;
                    boolean PnisSameValue = false;
                    if (currentMessage.getSnLists() != null && !currentMessage.getSnLists().isEmpty()
                            && preMessage.getSnLists() != null && !preMessage.getSnLists().isEmpty()) {
                        for (String currentSn : currentMessage.getSnLists().keySet()) {
                            for (String preSn : preMessage.getSnLists().keySet()) {
                                if (currentSn.equals(preSn)) {
                                    SnisSameKey = true;
                                } else {
                                    logger.error("Serialnumber is not match, current serialnumber:[{}], previous serialnumber:[{}]", currentSn, preSn);
                                }
                                if (currentMessage.getSnLists().get(currentSn).equals(preMessage.getSnLists().get(preSn))) {
                                    SnisSameValue = true;
                                } else {
                                    logger.error("Serialnumber value is not match, current serialnumber:[{}], previous serialnumber:[{}]", currentMessage.getSnLists().get(currentSn), preMessage.getSnLists().get(preSn));
                                }
                                break;
                            }
                        }
                    }
                    if (currentMessage.getPnLists() != null && !currentMessage.getPnLists().isEmpty()
                            && preMessage.getPnLists() != null && !preMessage.getPnLists().isEmpty()) {
                        for (String currentPn : currentMessage.getPnLists().keySet()) {
                            for (String prePn : preMessage.getPnLists().keySet()) {
                                if (currentPn.equals(prePn)) {
                                    PnisSameKey = true;
                                } else {
                                    logger.error("Product number is not match, current serialnumber:[{}], previous serialnumber:[{}]", currentPn, prePn);
                                }
                                if (currentMessage.getPnLists().get(currentPn).equals(preMessage.getPnLists().get(prePn))) {
                                    PnisSameValue = true;
                                } else {
                                    logger.error("Product number value is not match, current serialnumber:[{}], previous serialnumber:[{}]", currentMessage.getPnLists().get(currentPn), preMessage.getPnLists().get(prePn));
                                }
                                break;
                            }
                        }

                    }
                    if (SnisSameKey && SnisSameValue && PnisSameKey && PnisSameValue) {
                        return true;
                    }
            }
            }
        return false;
        }


    public static boolean validateSnIsExistMoresProduction(String sn) {
        DataSearchService dataSearchService = ApplicationBeanUtils.getBean(DataSearchService.class);
        List<SerialNumberDto> serialNumberDtoList = dataSearchService.findSnBySerialValue(sn);
        if (serialNumberDtoList != null && serialNumberDtoList.size() >= 2) {
            return true;
        }
        return false;
    }


    public static List<ProcessMessage> getProcessMessage() {
        SystemConfig systemConfig = ApplicationBeanUtils.getBean(SystemConfig.class);
        List<ProcessMessage> processMessageList = mapper.fromJson(systemConfig.getFlow(), mapper.contructCollectionType(List.class, ProcessMessage.class));
        return processMessageList;
    }

    public static List<ProcessMessage> getProcessSuMessage() {
        SystemConfig systemConfig = ApplicationBeanUtils.getBean(SystemConfig.class);
        List<ProcessMessage> processMessageList = mapper.fromJson(systemConfig.getFlowSu(), mapper.contructCollectionType(List.class, ProcessMessage.class));
        return processMessageList;
    }

    public static String validateInProcess(String stationId, TrackDto trackDto) {
        List<ProcessMessage> processMessageList = MessageUtils.getProcessMessage();
        if (processMessageList != null && !processMessageList.isEmpty()) {
            for (ProcessMessage processMessage : processMessageList) {
                if (stationId.equals(processMessage.getSid())) {
                    if (processMessage.getIn() != null && !processMessage.getIn().isEmpty()) {
                        for (BaseDto baseDto : processMessage.getIn()) {
                            if (baseDto.getKey().equals(stationId) && trackDto.getStatus().equals(AppConst.RESULT_DEBUG) && trackDto.getStatus().equals(baseDto.getValue())) {
                                return AppConst.RESULT_OK;
                            }
                            if (trackDto.getStatus().equals(baseDto.getValue()) && baseDto.getKey().equals(trackDto.getStationId())) {
                                return AppConst.RESULT_OK;
                            }
                        }
                    }
                }
            }
        }

        List<ProcessMessage> processSuMessageList = MessageUtils.getProcessSuMessage();
        if (processSuMessageList != null && !processSuMessageList.isEmpty()) {
            for (ProcessMessage processMessage : processSuMessageList) {
                if (stationId.equals(processMessage.getSid())) {
                    if (processMessage.getIn() != null && !processMessage.getIn().isEmpty()) {
                        for (BaseDto baseDto : processMessage.getIn()) {
                            if (baseDto.getKey().equals(stationId) && trackDto.getStatus().equals(AppConst.RESULT_DEBUG) && trackDto.getStatus().equals(baseDto.getValue())){
                                return AppConst.RESULT_OK;
                            }
                            if (trackDto.getStatus().equals(baseDto.getValue()) && baseDto.getKey().equals(trackDto.getStationId())) {
                                return AppConst.RESULT_OK;
                            }
                        }
                    }
                }
            }
        }
        logger.error("Into the process matching error.");
        return AppConst.RESULT_NG;
    }

    public static List<String> getLinkSns() {
        SystemConfig systemConfig = ApplicationBeanUtils.getBean(SystemConfig.class);
        if (StringUtils.isBlank(systemConfig.getLinkSns())) {
            logger.info("LinkSn is empty.");
            return null;
        }
        List<String> linkSnLists = Lists.newArrayList();
        String[] linkSns = systemConfig.getLinkSns().split(",");
        for (String linkSn : linkSns) {
            linkSnLists.add(linkSn);
        }
        return linkSnLists;
    }


    private static List<String> getStartFlags() {
        if (startFlags == null) {
            startFlags = Lists.newArrayList();
            startFlags.add(AppConst.START_VALIDATE_REQ);
            startFlags.add(AppConst.START_STATUS_REQ);
            startFlags.add(AppConst.START_DATA_REQ);
            startFlags.add(AppConst.START_HEARTBEAT);
            startFlags.add(AppConst.START_OFFLINE_REQ);

        }
        return  startFlags;
    }

    public static ReceiveMessage encodeHttpMessages(String message) throws Exception {
        ReceiveMessage receiveMessage = new ReceiveMessage();
        if (StringUtils.isBlank(message)) {
            logger.error("Message is empty.");
            return null;
        }
        message = message.trim();
        String endFlag = message.substring(message.length() - 1, message.length());
        String[] messages =  message.substring(0, message.length() - 1).split(";");
        String result = "";
        String outValue = "";
        if (messages == null || messages.length == 0) {
            logger.error("Message is empty.");
            return null;
        }
        String startFlag = messages[0];
        String stationId = messages[1];
        if (messages[0].equals(AppConst.START_STATUS_RESP)){
            result = messages[2];
        }else if(messages[0].equals(AppConst.START_VALIDATE_RESP) && !messages[2].equals(AppConst.RESULT_NG)){
            outValue = messages[3].split("=")[1];
            result = messages[4];
        }else{
            outValue = "null";
            result = messages[2];
        }
        if (stationId.equals(AppConst.STATION_0750)){
            receiveMessage.setFct(outValue);
        }else if (stationId.equals(AppConst.STATION_1050)){
            receiveMessage.setEol(outValue);
        }
        receiveMessage.setResult(result);
        receiveMessage.setStartFlag(startFlag);
        receiveMessage.setStationId(stationId);
        return receiveMessage;
    }
}
